Previous Book Contents Book Index Next

Inside Macintosh: Overview /
Chapter 4 - Events


Receiving Events

You receive events by calling an Event Manager routine, usually WaitNextEvent. When you ask for an event, the Event Manager returns the next available event according to its event priority. The Event Manager returns events in this order of priority:

  1. activate events
  2. mouse-down, mouse-up, key-down, key-up, and disk-inserted events in FIFO (first-in, first-out) order
  3. auto-key events
  4. update events (in front-to-back order of windows)
  5. operating-system events (suspend, resume, mouse-moved)
  6. high-level events
  7. null events

To retrieve an event, you pass the WaitNextEvent function an event record, defined by the EventRecord data type:

TYPE EventRecord =
   RECORD
      what:          Integer;       {event code}
      message:       LongInt;       {event message}
      when:          LongInt;       {ticks since startup}
      where:         Point;         {mouse location}
      modifiers:     Integer;       {modifier flags}
   END;
On return from WaitNextEvent, the what field of the event record contains an integer that specifies the type of event received. The Event Manager uses this set of predefined constants to indicate the event type:

CONST
   nullEvent         = 0;           {no other pending events}
   mouseDown         = 1;           {mouse button pressed}
   mouseUp           = 2;           {mouse button released}
   keyDown           = 3;           {key pressed}
   keyUp             = 4;           {key released}
   autoKey           = 5;           {key held down}
   updateEvt         = 6;           {a window needs updating}
   diskEvt           = 7;           {disk inserted}
   activateEvt       = 8;           {activate/deactivate window}
   osEvt             = 15;          {operating-system event}
   kHighLevelEvent   = 23;          {high-level event}
The message field of the event record contains additional information about the event. The interpretation of this field depends on the type of event you've received. For some events (such as null events, mouse-up, and mouse-down events), the value in the message field is undefined. For keyboard events, the message field indicates which key was pressed. For activate and update events, the message field contains a window pointer to the affected window. For disk-inserted events, the message field contains the drive number in the low-order word and the result code of the File Manager's attempt to mount that disk in that drive. Listing 4-3 illustrates how an application reads parts of the message field while handling disk-inserted events.

Listing 4-3 Handling disk-inserted events

PROCEDURE DoDiskEvent (myEvent: EventRecord);
   VAR
      myResult:   Integer;
      myPoint:    Point;
BEGIN
   IF HiWord(myEvent.message) <> noErr THEN
      BEGIN
         SetPt(myPoint, 100, 100);
         myResult := DIBadMount(myPoint, myEvent.message);
      END;
END;
If the disk was not successfully mounted (that is, if the high-order word of the message field does not contain noErr), then DoDiskEvent calls the system software routine DIBadMount to inform the user and allow the disk to be ejected or reformatted. (See the chapter "Disk Initialization Manager" in Inside Macintosh: Files for more information about handling disk-inserted events.)

The where field of the event record contains, for low-level events, the location of the cursor at the time the event was posted. You can use this information to determine where on the screen a mouse-down event occurred, for instance.

The modifiers field contains information about the state of the modifier keys and the mouse button at the time the event was posted. For activate events, this field also indicates whether the window should be activated or deactivated. (In System 7, it also indicates whether a mouse-down event caused your application to switch to the foreground.)

To handle an event, you simply take whatever action is appropriate for the kind of event it is. Listing 4-4 shows one way to structure an event-handling routine.

Listing 4-4 An event loop

PROCEDURE DoMainEventLoop;
   VAR
      myEvent:    EventRecord;
      gotEvent:   Boolean;                {is returned event for me?}
BEGIN
   REPEAT
      gotEvent := WaitNextEvent(everyEvent, myEvent, 15, NIL);
      IF NOT DoHandleDialogEvent(myEvent) THEN
         IF gotEvent THEN
            BEGIN
               CASE myEvent.what OF
                  mouseDown: 
                     DoMouseDown(myEvent);                  {see page 120}
                  keyDown, autoKey: 
                     DoKeyDown(myEvent);                    {see page 160}
                  updateEvt: 
                     DoUpdate(WindowPtr(myEvent.message));  {see page 124}
                  diskEvt: 
                     DoDiskEvent(myEvent);                  {see page 77}
                  activateEvt: 
                     DoActivate(WindowPtr(myEvent.message),
                                  myEvent.modifiers);       {see page 126}
                  osEvt: 
                     DoOSEvent(myEvent);                    {see page 171}
                  keyUp, mouseUp: 
                     ;
                  nullEvent: 
                     DoIdle(myEvent);                       {see page 173}
                  OTHERWISE
                     ;
               END; {CASE}
            END
         ELSE
            DoIdle(myEvent);
   UNTIL gDone;                        {loop until user quits}
END;
The event loop defined in Listing 4-4 repeatedly calls the WaitNextEvent function to retrieve the next available event. This function returns a value of FALSE if there are no events of the desired type (other than null events) pending for your application. Otherwise, WaitNextEvent returns TRUE.

After the next available event is retrieved, the DoMainEventLoop procedure calls the application-defined function DoHandleDialogEvent (defined in Listing 7-5 on page 141) to determine whether the event applies to a dialog box. The DoHandleDialogEvent function returns TRUE if it handled the event and FALSE otherwise.

Note
Dialog boxes receive special treatment because the system software automatically handles many user actions in dialog boxes. For example, the Dialog Manager handles update events for dialog boxes, and it calls the Control Manager to handle user actions affecting any controls in the dialog box.
If the event retrieved does not apply to a dialog box, and if it isn't a null event, then DoMainEventLoop branches into a Pascal CASE statement in which the labels are simply the predefined constants for each event type. As you can see, the event loop calls an application-defined routine to handle each particular kind of event. These routines are defined throughout this book.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
9 JUL 1996